package util

import java.lang.reflect.{Field, Modifier}
import java.lang.String

/**
 * <p>
 * Created by IntelliJ IDEA.
 * User: zslajchrt
 * Date: Feb 15, 2011
 * Time: 1:14:04 PM
 */

object StateHandler {
  def extractState(instance: AnyRef, transferTemplate: Class[_], topAncestor: Class[_]): InstanceState = {
    val superTemplate = transferTemplate.getSuperclass
    val superState = if (topAncestor.isAssignableFrom(superTemplate))
      extractState(instance, superTemplate, topAncestor)
    else null

    // extract the state
    var fieldMap: Map[String, AnyRef] = Map()
    transferTemplate.getDeclaredFields.foreach(field => {
      val mod = field.getModifiers
      if (!Modifier.isAbstract(mod) &&
              !Modifier.isFinal(mod) &&
              !Modifier.isInterface(mod) &&
              !Modifier.isNative(mod) &&
              !Modifier.isStatic(mod)) {
        field.setAccessible(true)
        val value = field.get(instance)
        fieldMap += (field.getName -> value)
      }
    })

    new InstanceState(fieldMap, transferTemplate.getName, superState)
  }

}

@serializable @SerialVersionUID(1L)
class InstanceState(val values: Map[String, AnyRef], val className: String, val superState: InstanceState) {
  def applyState(targetInstance: AnyRef, transferTemplate: Class[_], topAncestor: Class[_]) {
    assert(transferTemplate.getName == className, "template class " + transferTemplate.getName
            + " and state's class " + className + " do not match")

    if (superState != null)
      superState.applyState(targetInstance, transferTemplate.getSuperclass, topAncestor)

    // apply the state
    values.foreach((pair) => {
      val (fieldName, value) = pair
      val field: Field = transferTemplate.getDeclaredField(fieldName)
      field.setAccessible(true)
      field.set(targetInstance, value)
    })

  }
}